/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <math.h>
#include <sys/select.h>
#include <errno.h>
#include <pthread.h>
#include <securec.h>
#include <deque>
#include <time.h>
#include <pthread.h>

#include "hilog_wrapper.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
#include "securec.h"
#include "local_net/include/local_net_communication.h"
#include "local_net/include/local_net_dlist.h"
#include "local_net/include/local_net_udp.h"
#include "native_event/include/dm_native_event.h"
#include "local_net_utils.h"
#include "RecvUdpEpoll.h"

using namespace std;

#define DISC_PORT       50000
#define BC_SLEEP_TIME   5
#define EXEC_SUCC 0
#define EXEC_FAILED -1
#define BROADCAST_ARRSIZE 1024

const char *netDeviceName = "wlan0";  // 注：连接无线时用： "wlan0",有线使用："eth0";;

const char* ip3568 = "127.0.0.1";
int port3568 = 50000;
int g_udpFlag = 1;
int g_updateDevive = 1;

struct CommandStrData {
    napi_async_work asyncWork = nullptr;
    napi_deferred deferred = nullptr;
    napi_ref callback = nullptr;
    char args[128] = {0};
    int32_t argc;
    int32_t intervalTime;
    char latchOperateStr[16] = {0};
    char group[16] = {0};
    Response result;
    Node_t *deviceList;
};

// common logs
enum LOG_LEVEL {
    CENCTRL_DEBUG = 0,
    CENCTRL_INFO,
    CENCTRL_WARN,
    CENCTRL_ERROR,
    LOGLEVEL_NBR
};

const char* CENCTRL_LOG_TAG[LOGLEVEL_NBR] = {
    "CENCTRL_DEBUG",
    "CENCTRL_INFO",
    "CENCTRL_WARN",
    "CENCTRL_ERROR"
};

int loglevel = CENCTRL_DEBUG;

#define SET_LOG_LEVEL(lv) ((lv) < LOGLEVEL_NBR ? loglevel = (lv) : loglevel = CENCTRL_DEBUG)

#define LOG(LOGEVEL, fmt, args...) ({                                                       \
    if (LOGEVEL <= loglevel) {                                                              \
        printf("[%s][%s][%d]" fmt, CENCTRL_LOG_TAG[LOGEVEL], __func__, __LINE__, ##args);   \
    }                                                                                       \
})

static DmNativeEvent *g_DmNativeEvent = nullptr;
static bool g_CarAccessReg = false;
static bool g_DevUpdateReg = false;
static napi_value g_thisVar = nullptr;
napi_env g_Env;
static string g_LogRoute = "";

// ParkingApi
// 业务逻辑处理函数，由worker线程池调度执行。
static void getDeviceListExecuteCB(napi_env env, void *data)
{
    CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
    DestroyDlist(&commandStrData->deviceList);
    commandStrData->deviceList = CreateDlist();
    Node_t *onlineDevList = getOnlineDevList();

    if (onlineDevList) {
        // 循环 netOnlineDeviceDList 查找订阅
        Node_t *tmpNetOnlineDeviceDList = onlineDevList->after;
        NetBroadcastPara_t *tempNetBroPara = (NetBroadcastPara_t *)tmpNetOnlineDeviceDList->data;
        while (tempNetBroPara && tmpNetOnlineDeviceDList != onlineDevList) {
            InsertHdlist(commandStrData->deviceList, tempNetBroPara, sizeof(NetBroadcastPara_t));
            tmpNetOnlineDeviceDList = tmpNetOnlineDeviceDList->after;
            tempNetBroPara = (NetBroadcastPara_t *)tmpNetOnlineDeviceDList->data;
        }
        commandStrData->result.state = SUCCESS;
        commandStrData->result.result = "SUCCESS";
    } else {
        commandStrData->result.state = ERROR;
        commandStrData->result.result = "ERROR";
    }
}

static void getDeviceListPromiseCompleteCB(napi_env env, napi_status status, void *data)
{
    CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
    napi_value array = nullptr;
    napi_create_array(env, &array);
    int i = 0;

    Node_t *onlineDevList = getOnlineDevList();
    if (!onlineDevList) {
        return;
    }
    Node_t *tmpNetOnlineDeviceDList = commandStrData->deviceList->after;
    NetBroadcastPara_t *tempNetBroPara = (NetBroadcastPara_t *)tmpNetOnlineDeviceDList->data;

    while (tempNetBroPara && tmpNetOnlineDeviceDList != onlineDevList) {
        napi_value obj = nullptr;
        napi_value resName = nullptr;
        napi_value resDeviceType = nullptr;
        napi_value resID = nullptr;
        napi_value resDeviceState = nullptr;
        napi_value resGroup = nullptr;

        napi_create_string_utf8(env, tempNetBroPara->name, strlen(tempNetBroPara->name), &resName);
        napi_create_string_utf8(env, tempNetBroPara->type, strlen(tempNetBroPara->type), &resDeviceType);
        napi_create_string_utf8(env, tempNetBroPara->id, strlen(tempNetBroPara->id), &resID);
        if (tempNetBroPara->state == LOCAL_NET_ONLINE) {
            const char *onlineStr = "online";
            napi_create_string_utf8(env, onlineStr, strlen(onlineStr), &resDeviceState);
        } else {
            const char *offlineStr = "offline";
            napi_create_string_utf8(env, offlineStr, strlen(offlineStr), &resDeviceState);
        }
        napi_create_string_utf8(env, tempNetBroPara->group, strlen(tempNetBroPara->group), &resGroup);
        napi_create_object(env, &obj);
        napi_set_named_property(env, obj, "name", resName);
        napi_set_named_property(env, obj, "deviceType", resDeviceType);
        napi_set_named_property(env, obj, "id", resID);
        napi_set_named_property(env, obj, "state", resDeviceState);
        napi_set_named_property(env, obj, "group", resGroup);

        napi_set_element(env, array, i++, obj);

        tmpNetOnlineDeviceDList = tmpNetOnlineDeviceDList->after;
        tempNetBroPara = (NetBroadcastPara_t *)tmpNetOnlineDeviceDList->data;
    }
    napi_resolve_deferred(env, commandStrData->deferred, array);

    // 删除napi_ref对象
    if (commandStrData->callback != nullptr) {
        napi_delete_reference(env, commandStrData->callback);
    }
    // 删除异步工作项
    napi_delete_async_work(env, commandStrData->asyncWork);
    delete commandStrData;
}

/**
 * @brief parse unicast msg
 *
 * @param msg msg content
 * @return int8_t succ: 0 ,fail: -1
 */
static int8_t unicastOperateMsgParse(const char* msg)
{
    HILOG_INFO("ParkingSystem  unicastOperateMsgParse \r\n");
    addLogs("ParkingSystem  unicastOperateMsgParse");
    if (!msg) {
        return -1;
    }
    int8_t openFlag = -1;
    cJSON *unicastJson = cJSON_Parse(msg);
    if(!unicastJson) {
        HILOG_ERROR("ParkingSystem   licensePlateRecognition NULL POINT! \n");
        return -1;
    }
    HILOG_INFO("ParkingSystem   licensePlateRecognition:  #%{public}s", msg);
    addLogs("ParkingSystem   licensePlateRecognition:");
    addLogs(msg);

    // 查询是否车牌信息 carAccess
    cJSON *publishJson = cJSON_GetObjectItem(unicastJson, "publish");
    cJSON *group = cJSON_GetObjectItem(unicastJson, "group");  // group
    cJSON *params = cJSON_GetObjectItem(unicastJson, "params");

    HILOG_INFO("unicastOperateMsgParse publishJson: #%{public}s", cJSON_GetStringValue(publishJson));
    HILOG_INFO("unicastOperateMsgParse group: #%{public}s", cJSON_GetStringValue(group));
    HILOG_INFO("unicastOperateMsgParse params: #%{public}s", cJSON_GetStringValue(params));
    if (publishJson && params) {
      if (cJSON_GetStringValue(publishJson) && !strcmp("licensePlateRecognition",
                    cJSON_GetStringValue(publishJson))) {
          HILOG_INFO("ParkingSystem   publishJson->valuestring: licensePlateRecognition ");
          napi_value stateEventNapi;
          napi_value groupEventNapi;
          napi_value licensePlateEventNapi;
          cJSON *licensePlate = cJSON_GetObjectItem(params, "licensePlate");  // licensePlate
          const char *stateStr = "waiting";
          if (NULL == group) {
              HILOG_ERROR("   group NULL POINT! \n");
              return -1;
          }
          const char *groupStr = cJSON_GetStringValue(group);
          if (NULL == groupStr) {
              HILOG_ERROR("   groupStr NULL POINT! \n");
              return -1;
          }
          const char *licensePlateStr = cJSON_GetStringValue(licensePlate) ? cJSON_GetStringValue(licensePlate) : " ";
          napi_create_string_utf8(g_Env, licensePlateStr, strlen(licensePlateStr), &licensePlateEventNapi);
          napi_create_string_utf8(g_Env, groupStr, strlen(groupStr), &groupEventNapi);
          napi_create_string_utf8(g_Env, stateStr, strlen(stateStr), &stateEventNapi);
          if (g_CarAccessReg == true && g_DmNativeEvent != nullptr) {
              // 回调，返回车牌信息
              napi_value eventNapi[3] = {licensePlateEventNapi, groupEventNapi, stateEventNapi};
              HILOG_INFO("ParkingSystem   licensePlateRecognition  carAccess 3 eventNapi ");
              try {
                  g_DmNativeEvent->OnEvent("carAccess", 3, eventNapi);
              } catch(const std::exception &e) {
                  HILOG_ERROR("error onevent caAccess : ");
                  addLogs("error onevent caAccess : ");
              }
          }
          HILOG_INFO("ParkingSystem   licensePlateRecognition:  #%{public}s, \n", licensePlateStr);
          addLogs("licensePlateRecognition:");
          addLogs(licensePlateStr);

      } else if (cJSON_GetStringValue(publishJson) && !strcmp("latchChange", cJSON_GetStringValue(publishJson))) {
          if (params) {
              cJSON *boolOpenJson = cJSON_GetObjectItem(params, "latchState");
              if (boolOpenJson) {
                  if (!strcmp("open", cJSON_GetStringValue(boolOpenJson))) {
                      openFlag = 1;
                  } else {
                      openFlag = 0;
                  }
              }
          }

      } else if (cJSON_GetStringValue(publishJson) && !strcmp("carApproachDetect", cJSON_GetStringValue(publishJson))) {
          cJSON *carApproJson = cJSON_GetObjectItem(params, "detectResult");
          if (carApproJson == NULL) {
              return -1;
          }
          HILOG_INFO("ParkingSystem   carApproachDetect publishJson->valuestring:");
          addLogs("ParkingSystem   carApproachDetect publishJson->valuestring:");
          napi_value stateEventNapi;
          napi_value groupEventNapi;
          napi_value licensePlateEventNapi;

          const char *stateStr = cJSON_GetStringValue(carApproJson);
          const char *groupStr = cJSON_GetStringValue(group);
          if (NULL == groupStr || stateStr == NULL || strcmp(stateStr, "leave")) {
              HILOG_ERROR(" stateStr : %s! \n", stateStr ? stateStr : "NULL");
              return -1;
          }
          const char *licensePlateStr = " ";
          napi_create_string_utf8(g_Env, licensePlateStr, strlen(licensePlateStr), &licensePlateEventNapi);
          napi_create_string_utf8(g_Env, groupStr, strlen(groupStr), &groupEventNapi);
          napi_create_string_utf8(g_Env, stateStr, strlen(stateStr), &stateEventNapi);
          if (g_CarAccessReg == true && g_DmNativeEvent != nullptr) {
              HILOG_INFO("ParkingSystem   carApproachDetect g_DmNativeEvent OnEvent ");
              // 回调，返回车牌信息
              napi_value eventNapi[3] = {licensePlateEventNapi, groupEventNapi, stateEventNapi};
              try {
                  g_DmNativeEvent->OnEvent("carAccess", 3, eventNapi);
              } catch(const std::exception &e) {
                  HILOG_ERROR("error onevent caAccess : ");
                  addLogs("error onevent caAccess 316 : ");
              }
          }
      }
    }
    cJSON_Delete(unicastJson);
    return openFlag;
}

static int8_t msgRecv(const char *msg)
{
    if (!msg) {
        return -1;
    }
    int ret = unicastOperateMsgParse(msg);
    if (ret == 1) {
        // 添加处理执行 operate:"open" 的逻辑
        HILOG_INFO("ParkingSystem   latchChange latchState:open! \r\n");
    } else if (ret == 0) {
        // 添加处理执行 operate:"close" 逻辑
        HILOG_INFO("ParkingSystem   latchChange latchState:close! \r\n");
    } else {
      HILOG_INFO("ParkingSystem   unicastOperateMsgParse! \r\n");
        // 添加处理异常的逻辑
    }
    return ret;
}

static int8_t OnLocalNetDevListNoticeCb(Node_t *devList)
{
   if (!devList) {
      HILOG_INFO("ParkingSystem OnLocalNetDevListNoticeCb not start \r\n");
      return 0;
   }
   napi_value array = nullptr;
   napi_create_array(g_Env, &array);
   int i = 0;
   Node_t *onlineDevListHead = devList;
   Node_t *tmpNode = onlineDevListHead->after;

   while (tmpNode != onlineDevListHead) {
      if (tmpNode->data) {
          NetBroadcastPara_t *theNodeData = (NetBroadcastPara_t *)tmpNode->data;
          HILOG_INFO("ParkingSystem OnLocalNetDevListNoticeCb #%{public}s \r\n", theNodeData->name);
          napi_value obj = nullptr;
          napi_value resName = nullptr;
          napi_value resDeviceType = nullptr;
          napi_value resID = nullptr;
          napi_value resDeviceState = nullptr;
          napi_value resGroup = nullptr;

          napi_create_string_utf8(g_Env, theNodeData->name, strlen(theNodeData->name), &resName);
          napi_create_string_utf8(g_Env, theNodeData->type, strlen(theNodeData->type), &resDeviceType);
          napi_create_string_utf8(g_Env, theNodeData->id, strlen(theNodeData->id), &resID);
          if (theNodeData->state == LOCAL_NET_ONLINE) {
            const char *onlineStr = "online";
            napi_create_string_utf8(g_Env, onlineStr, strlen(onlineStr), &resDeviceState);
          } else {
            const char *offlineStr = "offline";
            napi_create_string_utf8(g_Env, offlineStr, strlen(offlineStr), &resDeviceState);
          }
          napi_create_string_utf8(g_Env, theNodeData->group, strlen(theNodeData->group), &resGroup);
          napi_create_object(g_Env, &obj);
          napi_set_named_property(g_Env, obj, "name", resName);
          napi_set_named_property(g_Env, obj, "deviceType", resDeviceType);
          napi_set_named_property(g_Env, obj, "id", resID);
          napi_set_named_property(g_Env, obj, "state", resDeviceState);
          napi_set_named_property(g_Env, obj, "group", resGroup);
          napi_set_element(g_Env, array, i++, obj);
      }
      tmpNode = tmpNode->after;
   }

   HILOG_INFO("ParkingSystem OnLocalNetDevListNoticeCb out of while \r\n");
   if (g_DevUpdateReg == true && g_DmNativeEvent != nullptr) {
      // 设备列表信息更新后，进入回调，返回设备列表信息
      napi_value result = nullptr;
      napi_create_object(g_Env, &result);
      napi_set_named_property(g_Env, result, "devicesUpdate", array);
      HILOG_INFO("ParkingSystem OnLocalNetDevListNoticeCb g_DmNativeEvent->OnEvent \r\n");
      try {
          g_DmNativeEvent->OnEvent("devicesUpdate", 1, &result);
      } catch(const std::exception &e) {
          HILOG_ERROR("error onevent devicesUpdate : ");
          addLogs("error onevent devicesUpdate 415: ");
      }
   }

   return 0;
}

// 业务逻辑处理函数，由worker线程池调度执行。
static void initExecuteCB(napi_env env, void *data)
{
    string logRoute = g_LogRoute + "/mytest.txt";
    CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
    /**
    * @brief 广播发送的设备信息+订阅、发布信息
    *
    {
      "device":{
          "name":"RK3568 parking background management system"
          "type" : "parkingSystem",
          "id" : "97234126",
          "priority": 250，
          "group" : "all",
      }，
      "subscribe" : [
        "carApproachDetect"，"licensePlateRecognition","latchChange"
      ],
          "publish" : ["latchControl"]
    }
    */
    char mac[32] = {};
    int getmacret = getLocalMacAddr(netDeviceName, mac, sizeof(mac));
    if(getmacret >= 0) {
      HILOG_INFO("ParkingSystem getmacret >= 0 \n");
        NetBroadcastPara_t *selfInfo = (NetBroadcastPara_t *)malloc(sizeof(NetBroadcastPara_t));
        // name
        strcpy(selfInfo->name, "RK3568 parking background management system");
        // id
        char idArr[512] = {0};
        sprintf(idArr, "%s", "parkingSystem_");
        sprintf(idArr, "%s", "all_");
        sprintf(idArr, "%s", mac);
        char sha256ID[1024] = {};
        StrSha256(idArr, strlen(idArr) - 1, sha256ID);
        HILOG_INFO("=ParkingSystem=    StrSha256  \n");
        strcpy(selfInfo->id, sha256ID);
        // type
        strcpy(selfInfo->type, "parkingSystem");
        // group
        strcpy(selfInfo->group, "all");
        // priority
        selfInfo->priority = 250;
        // state
        selfInfo->state = LOCAL_NET_ONLINE;
        // time
        gettimeofday(&(selfInfo->time), NULL);
        // subscribe
        selfInfo->subscribe = CreateDlist();
        if (selfInfo->subscribe) {
          const char* carApproStr = "carApproachDetect";
          InsertTdlist(selfInfo->subscribe, carApproStr, strlen(carApproStr) + 1);
          const char* licenseStr = "licensePlateRecognition";
          InsertTdlist(selfInfo->subscribe, licenseStr, strlen(licenseStr) + 1);
          // const char* latchStr = "latchChange";
          // InsertTdlist(selfInfo->subscribe, latchStr, strlen(latchStr) + 1);
        }
        // publish
        selfInfo->publish = CreateDlist();
        if (selfInfo->publish) {
          const char* latchContrStr = "latchControl";
          InsertHdlist(selfInfo->publish, latchContrStr, strlen(latchContrStr) + 1);
        }
        HILOG_INFO("==ParkingSystem    LocalNetSelfInfoSet  \n");
        // set local data
        if (LocalNetSelfInfoSet(selfInfo)) {
            // LOG_E("LocalNetSelfInfoSet failed!");
            return;
        }
        // 初始化回调函数
        LocalNetMsgRecvCbReg(msgRecv);
        // 初始化事件回调，设备状态变化时候回调
        LocalNetDevListNoticeCbReg(OnLocalNetDevListNoticeCb);
        // 初始化网络、开线程等
        LocalNetInit();
        HILOG_INFO("ParkingSystem    LocalNetInit  \n");
        commandStrData->result.state = SUCCESS;
        commandStrData->result.result = "SUCCESS";
        commandStrData->result.time = "1s";
    } else {
        commandStrData->result.state = ERROR;
        commandStrData->result.result = "NET FAIL";
        commandStrData->result.time = "0s";
    }
}

static void initPromiseCompleteCB(napi_env env, napi_status status, void *data)
{
  CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  napi_value result = nullptr;
  napi_value resState = nullptr;
  napi_value resResult = nullptr;
  napi_value resTime = nullptr;

  napi_create_int32(env, (int32_t)commandStrData->result.state, &resState);

  char tempChar[256] = {};
  strcpy(tempChar, commandStrData->result.result.c_str());
  napi_create_string_utf8(env, tempChar, strlen(tempChar), &resResult);

  bzero(tempChar, strlen(tempChar));
  strcpy(tempChar, commandStrData->result.time.c_str());
  napi_create_string_utf8(env, tempChar, strlen(tempChar), &resTime);

  napi_create_object(env, &result);
  napi_set_named_property(env, result, "state", resState);
  napi_set_named_property(env, result, "result", resResult);
  napi_set_named_property(env, result, "time", resTime);
  napi_resolve_deferred(env, commandStrData->deferred, result);

  // 删除napi_ref对象
  if (commandStrData->callback != nullptr) {
    napi_delete_reference(env, commandStrData->callback);
  }

  // 删除异步工作项
  napi_delete_async_work(env, commandStrData->asyncWork);
  delete commandStrData;
}

// 业务逻辑处理函数，由worker线程池调度执行。
static void controlDoorGateExecuteCB(napi_env env, void *data)
{
  CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  /**
   * @brief 有待发送的数据格式
   {
     publish:"latchControl",
     params:{
        group:"a"
        operate:"open"
     }
    }
   */
  char mac[32] = {};
  int getmacret = getLocalMacAddr(netDeviceName, mac, 32);
  if (getmacret >= 0) {
    cJSON *paramsMsg = cJSON_CreateObject();
    const char *publishMsg = "latchControl";
    if (paramsMsg) {
        cJSON_AddStringToObject(paramsMsg, "group", commandStrData->group);
    } else {
      commandStrData->result.stateStr = "offline";
      commandStrData->result.result = "cJSON_CreateObject ERROR";
      HILOG_ERROR("cJSON_CreateObject ERROR \r\n");
      return;
    }

    addLogs("latchOperateStr:");
    addLogs(commandStrData->latchOperateStr);

    if (!strcmp(commandStrData->latchOperateStr, "open")) {
          cJSON_AddStringToObject(paramsMsg, "operate", "open");
    } else if (!strcmp(commandStrData->latchOperateStr, "close")) {
          cJSON_AddStringToObject(paramsMsg, "operate", "close");
    } else {
      commandStrData->result.stateStr = "offline";
      commandStrData->result.result = "PARAM ERROR";
      HILOG_ERROR("PARAM ERROR \r\n");
      return;
    }
    char msgSndStr[256] = {0};
    char *tmpParamStr = cJSON_Print(paramsMsg);
    strcpy(msgSndStr, tmpParamStr);
    HILOG_INFO("ParkingSystem sendCmdMsg: %{public}s \r\n", tmpParamStr);
    HILOG_INFO("ParkingSystem publishMsg: %{public}s \r\n", publishMsg);
    addLogs("publishMsg:");
    addLogs(publishMsg);
    addLogs("sendCmdMsg:");
    addLogs(tmpParamStr);

    LocalNetMsgSend(publishMsg, msgSndStr);

    cJSON_Delete(paramsMsg);
    free(tmpParamStr);
    commandStrData->result.stateStr = "online";
    commandStrData->result.result = msgSndStr;
  } else {
    commandStrData->result.stateStr = "offline";
    commandStrData->result.result = "NET ERROR";
    HILOG_ERROR("NET ERROR \r\n");
  }
}

static void controlDoorGatePromiseCompleteCB(napi_env env, napi_status status, void *data)
{
    CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
    napi_value result = nullptr;
    napi_value resState = nullptr;
    napi_value resResult = nullptr;
    napi_value resTime = nullptr;

    char tempChar[256] = {};
    napi_create_int32(env, (int32_t)commandStrData->result.state, &resState);
    strcpy(tempChar, commandStrData->result.result.c_str());
    napi_create_string_utf8(env, tempChar, strlen(tempChar), &resResult);

    bzero(tempChar, strlen(tempChar));
    strcpy(tempChar, commandStrData->result.time.c_str());
    napi_create_string_utf8(env, tempChar, strlen(tempChar), &resTime);

    napi_create_object(env, &result);
    napi_set_named_property(env, result, "state", resState);
    napi_set_named_property(env, result, "result", resResult);
    napi_set_named_property(env, result, "time", resTime);

    napi_resolve_deferred(env, commandStrData->deferred, result);
    // 删除napi_ref对象
    if (commandStrData->callback != nullptr) {
      napi_delete_reference(env, commandStrData->callback);
    }

    // 删除异步工作项
    napi_delete_async_work(env, commandStrData->asyncWork);
    delete commandStrData;
}

static void onExecuteCB(napi_env env, void *data)
{
  CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  napi_value callback = nullptr;
  napi_get_reference_value(env, commandStrData->callback, &callback);
  string eventType = commandStrData->args;

  if (g_DmNativeEvent != nullptr) {
    if (commandStrData->argc == 3) {
      g_DmNativeEvent->On(eventType, callback, commandStrData->intervalTime);
    } else {
      g_DmNativeEvent->On(eventType, callback);
    }

    if (eventType == "carAccess") {
      g_CarAccessReg = true;
    } else if (eventType == "devicesUpdate") {
      g_DevUpdateReg = true;
    }
  }
}

static void onCallbackCompleteCB(napi_env env, napi_status status, void *data)
{
  CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  // 删除napi_ref对象
  if (commandStrData->callback != nullptr) {
    napi_delete_reference(env, commandStrData->callback);
  }

  // 删除异步工作项
  napi_delete_async_work(env, commandStrData->asyncWork);
  delete commandStrData;
}

static void offExecuteCB(napi_env env, void *data)
{
  CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);
  string eventType = commandStrData->args;

  if (g_DmNativeEvent != nullptr) {
    g_DmNativeEvent->Off(eventType);
  }

  if (eventType == "carAccess") {
      g_CarAccessReg = false;
  } else if (eventType == "devicesUpdate") {
    g_DevUpdateReg = false;
  }
}

static void offCallbackCompleteCB(napi_env env, napi_status status, void *data)
{
  CommandStrData *commandStrData = dynamic_cast<CommandStrData*>((CommandStrData *)data);

  // 删除napi_ref对象
  if (commandStrData->callback != nullptr) {
    napi_delete_reference(env, commandStrData->callback);
  }

  // 删除异步工作项
  napi_delete_async_work(env, commandStrData->asyncWork);
  delete commandStrData;
}

/**
 * @brief 向所有设备同步自己的ip地址(广播)
 *
 * @param env 用于存储JS虚拟机的上下文
 * @param info 传递函数调用时的上下文信息，如this指针、参数列表值等
 * @return napi_value 返回处理结果
 */
static napi_value init(napi_env env, napi_callback_info info)
{
  // 创建promise
  napi_value promise = nullptr;
  napi_deferred deferred = nullptr;
  NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));

  // 异步工作项上下文用户数据，传递到异步工作项的execute、complete之间传递数据
  CommandStrData *commandStrData = new CommandStrData {
      .asyncWork = nullptr,
      .deferred = deferred,
  };
  g_Env = env;

  // 创建async work，创建成功后通过最后一个参数(commandStrData->asyncWork)返回async work的handle
  g_DmNativeEvent = new DmNativeEvent(env, promise);

  // 获取日志文件路径
  napi_value result = nullptr;
  string root_path = "";
  size_t argc = 1;
  napi_value args;
  napi_get_cb_info(env, info, &argc, &args, &g_thisVar, nullptr);
  if (argc > 1) {
      return result;
  }
  g_CarAccessReg = false;
  g_DevUpdateReg = false;

  size_t len = 0;
  char path[1024] = {0};
  napi_get_value_string_utf8(env, args, nullptr, -1, &len);
  napi_get_value_string_utf8(env,args, path, len+1, &len);
  root_path += path;
  g_LogRoute = root_path;
  HILOG_INFO("ParkingSystem root_path： #%{public}s \n", root_path.c_str());

  napi_value resourceName = nullptr;
  napi_create_string_utf8(env, "init", NAPI_AUTO_LENGTH, &resourceName);
  napi_create_async_work(env, nullptr, resourceName, initExecuteCB, initPromiseCompleteCB,
          (void *)commandStrData, &commandStrData->asyncWork);

  // 将刚创建的async work加到队列，由底层去调度执行
  napi_queue_async_work(env, commandStrData->asyncWork);
  HILOG_INFO("ParkingSysteminit \n");

  // 返回promise
  return promise;
}

/**
 * @brief 控制门闸打开、关闭
 *
 * @param env 用于存储JS虚拟机的上下文
 * @param info 传递函数调用时的上下文信息，如this指针、参数列表值等
 * @return napi_value 返回处理结果
 */
static napi_value controlLatch(napi_env env, napi_callback_info info)
{
  // 获取2个参数，值的类型是js类型（napi_value）
  size_t argc = 2;
  napi_value args[2];
  napi_value thisArg = nullptr;
  NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));

  // 获取并判断js参数类型
  napi_valuetype valuetype0;
  NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
  napi_valuetype valuetype1;
  NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
  if (valuetype0 != napi_string || valuetype1 != napi_string) {
    napi_throw_type_error(env, nullptr, "Wrong arguments. 1 arg expected.");
    return nullptr;
  }

  // 创建promise
  napi_value promise = nullptr;
  napi_deferred deferred = nullptr;
  NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));

  // 异步工作项上下文用户数据，传递到异步工作项的execute、complete之间传递数据
  CommandStrData *commandStrData = new CommandStrData {
      .asyncWork = nullptr,
      .deferred = deferred,
  };

  // 将接收到的参数传入
  size_t getStrRes;
  NAPI_CALL(env, napi_get_value_string_utf8(env, args[1], commandStrData->latchOperateStr,
          (size_t)sizeof(commandStrData->latchOperateStr), &getStrRes));
  NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], commandStrData->group,
          (size_t)sizeof(commandStrData->group), &getStrRes));

  // 创建async work，创建成功后通过最后一个参数(commandStrData->asyncWork)返回async work的handle
  napi_value resourceName = nullptr;
  napi_create_string_utf8(env, "controlLatch", NAPI_AUTO_LENGTH, &resourceName);
  napi_create_async_work(env, nullptr, resourceName, controlDoorGateExecuteCB, controlDoorGatePromiseCompleteCB,
          (void *)commandStrData, &commandStrData->asyncWork);

  // 将刚创建的async work加到队列，由底层去调度执行
  napi_queue_async_work(env, commandStrData->asyncWork);

  // 返回promise
  return promise;
}

/**
 * @brief 获取设备列表 只返回一次结果，不同于on中不断的触发回调
 *
 * @param env 用于存储JS虚拟机的上下文
 * @param info 传递函数调用时的上下文信息，如this指针、参数列表值等
 * @return napi_value 返回处理结果 Array<DeviceInfo>
 */
static napi_value getDeviceList(napi_env env, napi_callback_info info)
{
  // 创建promise
  napi_value promise = nullptr;
  napi_deferred deferred = nullptr;
  NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));

  // 异步工作项上下文用户数据，传递到异步工作项的execute、complete之间传递数据
  CommandStrData *commandStrData = new CommandStrData {
      .asyncWork = nullptr,
      .deferred = deferred,
  };

  // 创建async work，创建成功后通过最后一个参数(commandStrData->asyncWork)返回async work的handle
  napi_value resourceName = nullptr;
  napi_create_string_utf8(env, "getDeviceList", NAPI_AUTO_LENGTH, &resourceName);
  napi_create_async_work(env, nullptr, resourceName, getDeviceListExecuteCB, getDeviceListPromiseCompleteCB,
        (void *)commandStrData, &commandStrData->asyncWork);

  // 将刚创建的async work加到队列，由底层去调度执行
  napi_queue_async_work(env, commandStrData->asyncWork);

  // 返回promise
  return promise;
}

/**
 * @brief Get the Hello String object
 *
 * @param env
 * @param info
 * @return napi_value
 */
static napi_value getHelloString(napi_env env, napi_callback_info info) {
  napi_value result;
  std::string words = "Hello World!";
  NAPI_CALL(env, napi_create_string_utf8(env, words.c_str(), words.length(), &result));
  return result;
}

/**
 * @brief  1.监听是否有车辆进入（1. 来自摄像头云端识别 2.来自自己本地识别）
 *         触发回调方式：
 *           1.1 车辆来了，有摄像头则获取到车牌识别结果后进入回调（携带识别结果），无则感应到车辆靠近则触发（无识别结果）
 *           1.2 车辆离开触发回调。
 *         2.订阅所有设备设备更新状态。
 * @param env
 * @param info
 * @return napi_value
 */
static napi_value on(napi_env env, napi_callback_info info) {
  // 获取3个参数，值的类型是js类型（napi_value）
  size_t argc = 3;
  napi_value args[3];
  napi_value thisArg = nullptr;
  NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));

  // 获取并判断js参数类型
  napi_valuetype valuetype0;
  NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
  napi_valuetype valuetype1;
  NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
  if (valuetype0 != napi_string || valuetype1 != napi_function) {
    napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");
    return NULL;
  }
  if (argc == 3) {
    napi_valuetype valuetype2;
    NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2));
    if (valuetype2 != napi_number) {
      napi_throw_type_error(env, nullptr, "Callback function expected.");
      return NULL;
    }
  }

  // 异步工作项上下文用户数据，传递到异步工作项的execute、complete中传递数据
  CommandStrData *commandStrData = new CommandStrData {
      .asyncWork = nullptr,
      .argc = argc,
  };

  // 将接收到的参数传入用户自定义上下文数据
  size_t getStrRes;
  NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], commandStrData->args,
          (size_t)sizeof(commandStrData->args), &getStrRes));
  NAPI_CALL(env, napi_create_reference(env, args[1], 1, &commandStrData->callback));
  if (argc == 3) {
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &commandStrData->intervalTime));
  }

  // 创建async work，创建成功后通过最后一个参数接收async work的handle
  napi_value resourceName = nullptr;
  napi_create_string_utf8(env, "on", NAPI_AUTO_LENGTH, &resourceName);
  napi_create_async_work(env, nullptr, resourceName, onExecuteCB, onCallbackCompleteCB, (void *)commandStrData,
                         &commandStrData->asyncWork);

  // 将刚创建的async work加到队列，由底层去调度执行
  napi_queue_async_work(env, commandStrData->asyncWork);

  // 原生方法返回空对象
  napi_value result = 0;
  NAPI_CALL(env, napi_get_null(env, &result));
  return result;
}

/**
 * @brief 1.取消车辆出入监听。
 *        2.取消所有设备设备更新状态监听。
 *
 * @param env
 * @param info
 * @return napi_value
 */
static napi_value off(napi_env env, napi_callback_info info) {
  // 获取3个参数，值的类型是js类型（napi_value）
  size_t argc = 2;
  napi_value args[2];
  napi_value thisArg = nullptr;
  NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));

  // 获取并判断js参数类型
  napi_valuetype valuetype0;
  NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
  napi_valuetype valuetype1;
  NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
  if (valuetype0 != napi_string || valuetype1 != napi_function) {
    napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");
    return NULL;
  }

  // 异步工作项上下文用户数据，传递到异步工作项的execute、complete中传递数据
  CommandStrData *commandStrData = new CommandStrData {
      .asyncWork = nullptr,
      .argc = argc,
  };

  // 将接收到的参数传入用户自定义上下文数据
  size_t getStrRes;
  NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], commandStrData->args,
          (size_t)sizeof(commandStrData->args), &getStrRes));
  NAPI_CALL(env, napi_create_reference(env, args[1], 1, &commandStrData->callback));

  // 创建async work，创建成功后通过最后一个参数接收async work的handle
  napi_value resourceName = nullptr;
  napi_create_string_utf8(env, "off", NAPI_AUTO_LENGTH, &resourceName);
  napi_create_async_work(env, nullptr, resourceName, offExecuteCB, offCallbackCompleteCB, (void *)commandStrData,
                         &commandStrData->asyncWork);

  // 将刚创建的async work加到队列，由底层去调度执行
  napi_queue_async_work(env, commandStrData->asyncWork);

  // 原生方法返回空对象
  napi_value result = 0;
  NAPI_CALL(env, napi_get_null(env, &result));
  return result;
}

/**
 * @brief 释放napi下各个线程 调用后意味着设备下线
 *
 * @param env
 * @param info
 * @return napi_value
 */
static napi_value release(napi_env env, napi_callback_info info)
{
    // 停止回调
    g_CarAccessReg = false;
    g_DevUpdateReg = false;
    // 关闭网络、停止线程等
    LocalNetDeinit();
    // 关闭日志
    closeLogs();
    // 返回结果
    napi_value result;
    std::string words = "release succeed!";
    NAPI_CALL(env, napi_create_string_utf8(env, words.c_str(), words.length(), &result));
    return result;
}

// napi_addon_register_func
static napi_value registerFunc(napi_env env, napi_value exports) {
  static napi_property_descriptor desc[] = {
      DECLARE_NAPI_FUNCTION("init", init),
      DECLARE_NAPI_FUNCTION("controlLatch", controlLatch),
      DECLARE_NAPI_FUNCTION("getDeviceList", getDeviceList),
      DECLARE_NAPI_FUNCTION("getHelloString", getHelloString),
      DECLARE_NAPI_FUNCTION("on", on),
      DECLARE_NAPI_FUNCTION("off", off),
      DECLARE_NAPI_FUNCTION("release", release),
  };
  NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
  return exports;
}

/* 定义napi module
 * nm_modname: 模块名称，对应eTS使用为import nm_modname from '@ohos.ohos_shared_library_name'
 *             示例对应为：import hellonapi from '@ohos.hellonapi'
 * nm_register_func：API注册函数
 */
static napi_module ParkingModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = registerFunc,
    .nm_modname = "ParkingApi",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

// ability module register
extern "C" __attribute__((constructor)) void ParkingModuleRegister() {
    napi_module_register(&ParkingModule);
}
